Skip to content

Exercises

Sidenote types

On this course platform, I have 4 different “types” of Sidenote components, depending on the status of the thing happening:

In this exercise, we'll update our simplified Sidenote component to support a new type prop. This prop will be used to apply a dynamic CSS class.

Here's the markup we want to wind up with:

<aside class="wrapper notice">
<h3>This is an informational sidenote.</h3>
</aside>
<aside class="wrapper success">
<h3>This is a success sidenote!</h3>
</aside>

The wrapper class contains "shared" styles, things like the amount of padding, or the thickness of the border. The type classes like notice and success contain the category-specific styles (eg. background color).

In this exercise, you'll implement this pattern using CSS Modules. All of the styles have been provided. Your task is to apply the correct class name based on the type prop.

Acceptance criteria:

  • All sidenotes should have the wrapper class applied.
  • The type property of the Sidenote should apply an additional class, which changes the color of the background and border.

Code Playground

import styles from './Sidenote.module.css';

function Sidenote({ type, title, children }) {
return (
<aside>
<h3 className={styles.title}>{title}</h3>
<p>{children}</p>
</aside>
);
}

export default Sidenote;

Solution:

Video Summary

To keep things simple, I like to structure things so that the name of the type (eg. “notice”) is identical to its corresponding CSS class (eg. .notice). That way, I don't have to map the type onto a particular class, I can use the raw value.

In a pure CSS context, we could solve this with string interpolation, like this:

const className = `wrapper ${type}`;

Because we're using CSS Modules, though, we need to read those names off of the styles object:

import styles from './Sidenote.module.css';
const className = `${styles.wrapper} ${styles[type]}`;

Be sure to use the square brackets for styles[type] and not styles.type.

Important thing to realize: The order of the classes doesn't matter, in terms of the className prop. These two strings will always produce an identical result:

const className1 = `${styles.wrapper} ${styles[type]}`;
const className2 = `${styles[type]} ${styles.wrapper}`;

The thing that matters is the order of the definitions in the stylesheet. The .wrapper rule has to come above the 4 variants for the styles to be applied in the correct order.

This isn't a weird “CSS Modules” thing, this is how it works in CSS.

Movie ratings animation

Let's suppose we're building a site that'll help people find new movies to watch.

We're displaying some basic information about each movie, including a rating (sourced from Rotten Tomatoes).

Let's do something fun. For movies that have a rating of at least 9.0, we want to add an animation to the rating number:

The idea is to highlight movies with great ("glowing") reviews, to make them stand out.

A CSS class has been provided, glowingReview. You'll need to apply this to all ratings that are 9 or above. Don't be afraid to make changes to the markup for this!

Code Playground

import React from 'react';

import styles from './Movie.module.css';

// Your mission:
// Apply the 'glowingReview' CSS class to the
// movie rating when it's 9 or higher.

function Movie({ movie }) {
return (
<article className={styles.movie}>
<div className={styles.thumbnailWrapper}>
<img
alt="Movie poster"
src={movie.posterSrc}
/>
</div>
<div className={styles.textWrapper}>
<h2>{movie.title}</h2>
<p className={styles.synopsis}>
{movie.synopsis}
</p>
<p>
<strong>Rating:</strong> {movie.rating}
</p>
</div>
</article>
);
}

export default Movie;

Solution: